🎖️GitЯра🎖️
Commit 1c3784235e7e20ed88e054097d2e7addbff92dc3
Parents : 9bc1b87
Author : Mac DeCourcy <49794076+mdecourcy@users.noreply.github.com>
Signature : Signature validation error
Date : 2025-11-26T17:45:09-08:00
Committer : GitHub <noreply@github.com>
Date : 2025-11-27T01:45:09Z
fix: Multiple bugs - settings text fields, dropdowns, missing override duty cycle, and MQTT icon display (#3833)
Changes
9 files changed, 58 insertions(+), 55 deletions(-)
Diff
diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
index 12946a2d85..4a23cdf1f2 100644
--- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
+++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
@@ -721,6 +721,7 @@ class MeshService : Service() {
rssi = packet.rxRssi,
replyId = data.replyId,
relayNode = packet.relayNode,
+ viaMqtt = packet.viaMqtt,
)
}
diff --git a/core/database/src/main/kotlin/org/meshtastic/core/database/entity/Packet.kt b/core/database/src/main/kotlin/org/meshtastic/core/database/entity/Packet.kt
index 27801bf638..e5f6866c21 100644
--- a/core/database/src/main/kotlin/org/meshtastic/core/database/entity/Packet.kt
+++ b/core/database/src/main/kotlin/org/meshtastic/core/database/entity/Packet.kt
@@ -52,7 +52,7 @@ data class PacketEntity(
packetId = packetId,
emojis = reactions.toReaction(getNode),
replyId = data.replyId,
- viaMqtt = node.viaMqtt,
+ viaMqtt = data.viaMqtt,
relayNode = data.relayNode,
relays = data.relays,
)
diff --git a/core/model/src/main/kotlin/org/meshtastic/core/model/DataPacket.kt b/core/model/src/main/kotlin/org/meshtastic/core/model/DataPacket.kt
index a9b0743b1f..c1d9577d39 100644
--- a/core/model/src/main/kotlin/org/meshtastic/core/model/DataPacket.kt
+++ b/core/model/src/main/kotlin/org/meshtastic/core/model/DataPacket.kt
@@ -63,6 +63,7 @@ data class DataPacket(
var replyId: Int? = null, // If this is a reply to a previous message, this is the ID of that message
var relayNode: Int? = null,
var relays: Int = 0,
+ var viaMqtt: Boolean = false, // True if this packet passed via MQTT somewhere along its path
) : Parcelable {
/** If there was an error with this message, this string describes what was wrong. */
diff --git a/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/EditTextPreference.kt b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/EditTextPreference.kt
index 6f90570bd8..3e366d062d 100644
--- a/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/EditTextPreference.kt
+++ b/core/ui/src/main/kotlin/org/meshtastic/core/ui/component/EditTextPreference.kt
@@ -163,6 +163,7 @@ fun EditTextPreference(
onValueChanged: (Double) -> Unit,
modifier: Modifier = Modifier,
summary: String? = null,
+ onFocusChanged: (FocusState) -> Unit = {},
) {
var valueState by remember(value) { mutableStateOf(value.toString()) }
val decimalSeparators = setOf('.', ',', '٫', '、', '·') // set of possible decimal separators
@@ -185,7 +186,7 @@ fun EditTextPreference(
}
}
},
- onFocusChanged = {},
+ onFocusChanged = onFocusChanged,
modifier = modifier,
)
}
diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/CannedMessageConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/CannedMessageConfigItemList.kt
index 922477f082..6c38888f16 100644
--- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/CannedMessageConfigItemList.kt
+++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/CannedMessageConfigItemList.kt
@@ -72,6 +72,8 @@ fun CannedMessageConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(),
enabled = state.connected,
responseState = state.responseState,
onDismissPacketResponse = viewModel::clearPacketResponse,
+ additionalDirtyCheck = { messagesInput != messages },
+ onDiscard = { messagesInput = messages },
onSave = {
if (messagesInput != messages) {
viewModel.setCannedMessages(messagesInput)
diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/ExternalNotificationConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/ExternalNotificationConfigItemList.kt
index f4b83da399..e02fa7b4ce 100644
--- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/ExternalNotificationConfigItemList.kt
+++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/ExternalNotificationConfigItemList.kt
@@ -130,6 +130,8 @@ fun ExternalNotificationConfigScreen(
enabled = state.connected,
responseState = state.responseState,
onDismissPacketResponse = viewModel::clearPacketResponse,
+ additionalDirtyCheck = { ringtoneInput != ringtone },
+ onDiscard = { ringtoneInput = ringtone },
onSave = {
if (ringtoneInput != ringtone) {
viewModel.setRingtone(ringtoneInput)
@@ -259,7 +261,7 @@ fun ExternalNotificationConfigScreen(
DropDownPreference(
title = stringResource(Res.string.output_duration_milliseconds),
items = outputItems.map { it.value to it.toDisplayString() },
- selectedItem = formState.value.outputMs,
+ selectedItem = formState.value.outputMs.toLong(),
enabled = state.connected,
onItemSelected = { formState.value = formState.value.copy { outputMs = it.toInt() } },
)
@@ -268,7 +270,7 @@ fun ExternalNotificationConfigScreen(
DropDownPreference(
title = stringResource(Res.string.nag_timeout_seconds),
items = nagItems.map { it.value to it.toDisplayString() },
- selectedItem = formState.value.nagTimeout,
+ selectedItem = formState.value.nagTimeout.toLong(),
enabled = state.connected,
onItemSelected = { formState.value = formState.value.copy { nagTimeout = it.toInt() } },
)
diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/LoRaConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/LoRaConfigItemList.kt
index d8702e254d..a83dba3823 100644
--- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/LoRaConfigItemList.kt
+++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/LoRaConfigItemList.kt
@@ -47,6 +47,7 @@ import org.meshtastic.core.strings.lora
import org.meshtastic.core.strings.modem_preset
import org.meshtastic.core.strings.ok_to_mqtt
import org.meshtastic.core.strings.options
+import org.meshtastic.core.strings.override_duty_cycle
import org.meshtastic.core.strings.override_frequency_mhz
import org.meshtastic.core.strings.pa_fan_disabled
import org.meshtastic.core.strings.region_frequency_plan
@@ -169,6 +170,14 @@ fun LoRaConfigScreen(viewModel: RadioConfigViewModel, onBack: () -> Unit) {
containerColor = CardDefaults.cardColors().containerColor,
)
HorizontalDivider()
+ SwitchPreference(
+ title = stringResource(Res.string.override_duty_cycle),
+ checked = formState.value.overrideDutyCycle,
+ enabled = state.connected,
+ onCheckedChange = { formState.value = formState.value.copy { overrideDutyCycle = it } },
+ containerColor = CardDefaults.cardColors().containerColor,
+ )
+ HorizontalDivider()
val hopLimitItems = remember { hopLimits }
DropDownPreference(
title = stringResource(Res.string.hop_limit),
diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PositionConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PositionConfigItemList.kt
index 2a7c6e2a02..1c43ba1a09 100644
--- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PositionConfigItemList.kt
+++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/PositionConfigItemList.kt
@@ -149,6 +149,8 @@ fun PositionConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBa
enabled = state.connected,
responseState = state.responseState,
onDismissPacketResponse = viewModel::clearPacketResponse,
+ additionalDirtyCheck = { locationInput != currentPosition },
+ onDiscard = { locationInput = currentPosition },
onSave = {
if (formState.value.fixedPosition) {
if (locationInput != currentPosition) {
@@ -233,9 +235,9 @@ fun PositionConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBa
value = locationInput.latitude,
enabled = state.connected,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
- onValueChanged = { value ->
- if (value >= -90 && value <= 90.0) {
- locationInput = locationInput.copy(latitude = value)
+ onValueChanged = { lat: Double ->
+ if (lat >= -90 && lat <= 90.0) {
+ locationInput = locationInput.copy(latitude = lat)
}
},
)
@@ -245,9 +247,9 @@ fun PositionConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBa
value = locationInput.longitude,
enabled = state.connected,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
- onValueChanged = { value ->
- if (value >= -180 && value <= 180.0) {
- locationInput = locationInput.copy(longitude = value)
+ onValueChanged = { lon: Double ->
+ if (lon >= -180 && lon <= 180.0) {
+ locationInput = locationInput.copy(longitude = lon)
}
},
)
@@ -257,7 +259,7 @@ fun PositionConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBa
value = locationInput.altitude,
enabled = state.connected,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
- onValueChanged = { value -> locationInput = locationInput.copy(altitude = value) },
+ onValueChanged = { alt: Int -> locationInput = locationInput.copy(altitude = alt) },
)
HorizontalDivider()
TextButton(
diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/RadioConfigScreenList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/RadioConfigScreenList.kt
index 128761f34c..1ac9ce5160 100644
--- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/RadioConfigScreenList.kt
+++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/RadioConfigScreenList.kt
@@ -22,20 +22,14 @@ import androidx.compose.animation.expandIn
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkOut
-import androidx.compose.animation.slideInVertically
-import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.dp
@@ -59,6 +53,8 @@ fun <T : MessageLite> RadioConfigScreenList(
enabled: Boolean,
onSave: (T) -> Unit,
modifier: Modifier = Modifier,
+ additionalDirtyCheck: () -> Boolean = { false },
+ onDiscard: () -> Unit = {},
content: LazyListScope.() -> Unit,
) {
val focusManager = LocalFocusManager.current
@@ -81,48 +77,37 @@ fun <T : MessageLite> RadioConfigScreenList(
)
},
) { innerPadding ->
- val showFooterButtons = configState.isDirty
+ val showFooterButtons = configState.isDirty || additionalDirtyCheck()
- Box(modifier = Modifier.padding(innerPadding)) {
- LazyColumn(
- modifier = Modifier.fillMaxSize(),
- contentPadding = PaddingValues(16.dp),
- verticalArrangement = Arrangement.spacedBy(16.dp),
- ) {
- content()
+ LazyColumn(
+ modifier = Modifier.padding(innerPadding).fillMaxSize(),
+ contentPadding = PaddingValues(16.dp),
+ verticalArrangement = Arrangement.spacedBy(16.dp),
+ ) {
+ content()
- item {
- AnimatedVisibility(
- visible = showFooterButtons,
- modifier = Modifier.align(Alignment.BottomCenter),
- enter = expandIn(),
- exit = shrinkOut(),
- ) {
- Spacer(modifier = Modifier.height(64.dp))
- }
+ item {
+ AnimatedVisibility(
+ visible = showFooterButtons,
+ enter = fadeIn() + expandIn(),
+ exit = fadeOut() + shrinkOut(),
+ ) {
+ PreferenceFooter(
+ enabled = enabled && showFooterButtons,
+ negativeText = stringResource(Res.string.discard_changes),
+ onNegativeClicked = {
+ focusManager.clearFocus()
+ configState.reset()
+ onDiscard()
+ },
+ positiveText = stringResource(Res.string.save_changes),
+ onPositiveClicked = {
+ focusManager.clearFocus()
+ onSave(configState.value)
+ },
+ )
}
}
-
- AnimatedVisibility(
- visible = showFooterButtons,
- modifier = Modifier.align(Alignment.BottomCenter),
- enter = fadeIn() + slideInVertically(initialOffsetY = { it }),
- exit = fadeOut() + slideOutVertically(targetOffsetY = { it }),
- ) {
- PreferenceFooter(
- enabled = enabled && configState.isDirty,
- negativeText = stringResource(Res.string.discard_changes),
- onNegativeClicked = {
- focusManager.clearFocus()
- configState.reset()
- },
- positiveText = stringResource(Res.string.save_changes),
- onPositiveClicked = {
- focusManager.clearFocus()
- onSave(configState.value)
- },
- )
- }
}
}
}
Served by rngit 1.5.0 - Generated in 0.16s